mod match_route;

use std::str::FromStr;

use crate::errors::MockProxyError;
use crate::{config::app::App, mock_routes};

use axum::http;
use axum::http::header::CONTENT_TYPE;
use axum::{
    extract,
    http::{HeaderMap, HeaderName, HeaderValue, StatusCode},
    response::IntoResponse,
    Extension,
};

pub async fn match_route(req: extract::Request) -> impl IntoResponse {
    let mut headers: HeaderMap = HeaderMap::new();

    match mock_routes::ROUTERS.lock().await.search(req.uri().path()) {
        Some(route) => {
            if req.method().eq(route.method.as_str()) {
                for (key, value) in route.headers {
                    headers.insert(
                        HeaderName::try_from(key.as_str()).unwrap(),
                        HeaderValue::from_str(value.as_str()).unwrap(),
                    );
                }
                let code = StatusCode::from_u16(route.status_code as u16).unwrap();
                return (code, headers, route.content.clone());
            }
            (
                StatusCode::METHOD_NOT_ALLOWED,
                headers,
                MockProxyError::MethodNotAllowed(route.method).to_string(),
            )
        }
        None => (
            StatusCode::NOT_FOUND,
            headers,
            MockProxyError::NotFound(req.uri().path().to_string()).to_string(),
        ),
    }
}

pub async fn index(Extension(app): Extension<App>, req: extract::Request) -> impl IntoResponse {
    let mut headers: HeaderMap = HeaderMap::new();
    if let Ok(method) = http::Method::from_str(req.method().as_str()) {
        match method {
            http::Method::GET => {
                headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/text"));
                return (StatusCode::OK, headers, "Hello World".to_string());
            }
            http::Method::POST => {
                headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
                let appjson = serde_json::json!(app.copy_to_echo());
                return (StatusCode::OK, headers, appjson.to_string());
            }
            _ => {
                headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/text"));
                return (
                    StatusCode::METHOD_NOT_ALLOWED,
                    headers,
                    "Unexpected Method".to_string(),
                );
            }
        }
    };
    headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/text"));
    (
        StatusCode::METHOD_NOT_ALLOWED,
        headers,
        "Unexpected Method".to_string(),
    )
}
